package com.ymt.bpm.service.platform.fauth.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ymt.bpm.dao.MDao;
import com.ymt.bpm.dao.Mapper;
import com.ymt.bpm.model.Const.Oplog;
import com.ymt.bpm.model.POrg;
import com.ymt.bpm.model.POrgPos;
import com.ymt.bpm.model.POrgUser;
import com.ymt.bpm.model.POrgUserPos;
import com.ymt.bpm.service.platform.fauth.FaOrgService;
import com.ymt.bpm.service.platform.log.OpLogService;
import com.ymt.bpm.util.Const;
import com.ymt.bpm.util.DateUtil;
import com.ymt.bpm.util.DhxUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by Johnny on 2017/2/15.
 */
@Service
public class FaOrgServiceImpl implements FaOrgService {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private MDao mDao;

    @Autowired
    private OpLogService oplog;

    @Override
    public JSONArray selectAllByTenant(String tenantId, int timezoneOffset) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        List<POrg> list = mDao.selectList(Mapper.POrgMapper, "selectAllByTenant", paramMap);
        JSONArray rtn = new JSONArray();
        if (list!=null && list.size()>0) {
            for (POrg org : list) {
                JSONObject node = beanToJSON(org, timezoneOffset);
                rtn.add(node);
            }
        }
        return rtn;
    }

    @Override
    public JSONArray selectAllByTenantWithPos(String tenantId, int timezoneOffset) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        List<POrg> list = mDao.selectList(Mapper.POrgMapper, "selectAllByTenant", paramMap);
        JSONArray rtn = new JSONArray();
        if (list!=null && list.size()>0) {
            for (POrg org : list) {
                JSONObject node = beanToJSON(org, timezoneOffset);
                rtn.add(node);
            }
        }
        List<Map<String, Object>> listPos = mDao.selectList("POrgPosMapper", "selectAllByTenant", paramMap);
        if (list!=null && listPos.size()>0) {
            for (Map<String, Object> pos : listPos) {
                JSONObject node = posBeanToJSON(pos, timezoneOffset);
                rtn.add(node);
            }
        }
        return rtn;
    }

    @Override
    public String checkName(String tenantId, String parentId, String orgId, String orgName) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("parentId", parentId);
        paramMap.put("orgId", orgId);
        paramMap.put("orgName", orgName);
        POrg org = mDao.selectOne(Mapper.POrgMapper, "checkName", paramMap);
        return Boolean.toString(org==null);
    }

    @Override
    public JSONObject save(String tenantId, String loginName, String displayName, POrg org, int timezoneOffset) {
        if (tenantId!=null) {
            org.setTenantId(Integer.parseInt(tenantId));
        }
        int rs = 0;
        if (org.getOrgId()!=null && org.getOrgId().length()>0) {
            org.setParentId(null);//ensure do not update parentid to empty string
            org.setUpdateTime(DateUtil.getGMTDate());
            org.setUpdator(loginName);
            org.setUpdatorName(displayName);
            rs = mDao.update(Mapper.POrgMapper, "updateByPrimaryKeySelective", org);
            org = get(tenantId, org.getOrgId());
            
            //记录日志
            oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.CREATE, Oplog.CODE.ORG, org.getOrgName());
        } else {
            org.setOrgId("ORG-"+ UUID.randomUUID().toString());
            org.setCreateTime(DateUtil.getGMTDate());
            org.setCreator(loginName);
            org.setCreatorName(displayName);
            rs = mDao.insert(Mapper.POrgMapper, "insertSelective", org);

            //记录日志
            oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.UPDATE, Oplog.CODE.ORG, org.getOrgName());
        }
        JSONObject rtn = new JSONObject();
        rtn.put("result", rs);
        rtn.put("org", beanToJSON(org, timezoneOffset));
        return rtn;
    }

    @Override
    public POrg get(String tenantId, String orgId) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("orgId", orgId);
        return mDao.selectOne(Mapper.POrgMapper, "selectByPrimaryKey", paramMap);
    }

    @Override
    public JSONObject del(String tenantId, String loginName, String displayName, String orgId) {
        JSONObject rtn = new JSONObject();
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("orgId", orgId);

        POrg org = mDao.selectOne(Mapper.POrgMapper, "selectByPrimaryKey", paramMap);

        int count = mDao.selectOne(Mapper.POrgMapper, "countChildren", paramMap);
        if (count>0) {
            rtn.put("msg", "hasChildren");
            return rtn;
        }
        count = mDao.selectOne(Mapper.POrgUserMapper, "countOrgUsers", paramMap);
        if (count>0) {
            rtn.put("msg", "hasUsers");
            return rtn;
        }
        int rs = mDao.delete(Mapper.POrgMapper, "deleteByPrimaryKey", paramMap);
        if (rs>0) {
            rs += mDao.delete("POrgPosMapper", "deleteByOrgId", paramMap);
        }
        rtn.put(Const.AJAX_RESULT, rs);

        //记录日志
        oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.DELETE, Oplog.CODE.ORG, org.getOrgName());
        
        return rtn;
    }

    @Override
    public JSONObject usersInOrg(String tenantId, String orgId,
                                                int offset,
                                                int limit,
                                                String sort,
                                                String order) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("orgId", orgId);
        paramMap.put("sort", sort);
        paramMap.put("order", order);
        PageHelper.offsetPage(offset, limit);
        List<Map<String, Object>> list = mDao.selectList(Mapper.PUserMapper, "selectUsersByOrg", paramMap);
        if (list!=null && list.size()>0) {
            for (Map<String, Object> row : list) {
                row.put("_ITEM_NO", ++offset);
                row.remove("PASSWORD");
            }
        }
        PageInfo page = new PageInfo(list);
        JSONObject rtn = new JSONObject();
        rtn.put("total", page.getTotal());
        rtn.put("rows", list);
        return rtn;
    }

    @Override
    public JSONObject usersInOrgPos(String tenantId, String orgId, String posId,
                                                   int offset,
                                                   int limit,
                                                   String sort,
                                                   String order) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("orgId", orgId);
        paramMap.put("posId", posId);
        paramMap.put("sort", sort);
        paramMap.put("order", order);
        PageHelper.offsetPage(offset, limit);
        List<Map<String, Object>> list = mDao.selectList(Mapper.PUserMapper, "selectUsersByOrgPos", paramMap);
        if (list!=null && list.size()>0) {
            for (Map<String, Object> row : list) {
                row.put("_ITEM_NO", ++offset);
                row.remove("PASSWORD");
            }
        }
        PageInfo page = new PageInfo(list);
        JSONObject rtn = new JSONObject();
        rtn.put("total", page.getTotal());
        rtn.put("rows", list);
        return rtn;
    }

    @Override
    public int addPosition(String tenantId, String loginName, String displayName, String orgId, String posId) {
        POrgPos op = new POrgPos();
        op.setTenantId(tenantId);
        op.setOrgId(orgId);
        op.setPosId(posId);
        int rs = mDao.insert("POrgPosMapper", "insert", op);

        //记录日志
        oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.CREATE, Oplog.CODE.ORGPOS, null);

        return rs;
    }

    @Override
    public int deletePosition(String tenantId, String loginName, String displayName, String orgId, String posId) {
        //delete org-pos
        POrgPos op = new POrgPos();
        op.setTenantId(tenantId);
        op.setOrgId(orgId);
        op.setPosId(posId);
        int rs = mDao.delete("POrgPosMapper", "deleteByPrimaryKey", op);
        //delete org-pos-user
        POrgUserPos oup = new POrgUserPos();
        oup.setTenantId(tenantId);
        oup.setOrgId(orgId);
        oup.setPosId(posId);
        rs +=  mDao.insert(Mapper.POrgUserPosMapper, "deleteByObj", oup);

        //记录日志
        oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.DELETE, Oplog.CODE.ORGPOS, null);

        return rs;
    }

    @Override
    public JSONObject addPositionUser(String tenantId, String loginName, String displayName,
                                      String orgId, String posId, String userId) {
        JSONObject rtn = new JSONObject();
        int rs = 0;
        if (posId!=null && posId.length()>0) {
            POrgUserPos oup = new POrgUserPos();
            oup.setTenantId(tenantId);
            oup.setOrgId(orgId);
            oup.setPosId(posId);
            oup.setUserId(userId);

            //check exists
            POrgUserPos existing = mDao.selectOne(Mapper.POrgUserPosMapper, "selectByObj", oup);
            if (existing!=null && existing.getUpId()!=null) {
                rtn.put("userExists", true);
                return rtn;
            }

            oup.setUpId("OPU-"+UUID.randomUUID().toString());
            rs = mDao.insert(Mapper.POrgUserPosMapper, "insert", oup);

            //记录日志
            oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.CREATE, Oplog.CODE.POSUSER, userId);
        } else {
            POrgUser ou = new POrgUser();
            ou.setTenantId(tenantId);
            ou.setOrgId(orgId);
            ou.setUserId(userId);

            //check exists
            POrgUser existing = mDao.selectOne(Mapper.POrgUserMapper, "selectByObj", ou);
            if (existing!=null && existing.getOrgId()!=null) {
                rtn.put("userExists", true);
                return rtn;
            }

            int count = mDao.selectOne(Mapper.POrgUserMapper, "countExistingUserOrg", ou);
            if (count>0) {
                ou.setOrgRank("0");
            }
            rs = mDao.insert(Mapper.POrgUserMapper, "insertSelective", ou);

            //记录日志
            oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.CREATE, Oplog.CODE.ORGUSER, userId);
        }
        rtn.put("result", rs);
        return rtn;
    }

    @Override
    public int deleteOrgUser(String tenantId, String loginName, String displayName,
                             String orgId, String userId) {
        POrgUser ou = new POrgUser();
        ou.setTenantId(tenantId);
        ou.setOrgId(orgId);
        ou.setUserId(userId);
        int ret = mDao.delete(Mapper.POrgUserMapper, "deleteByObj", ou);
        ret += deletePositionUser(tenantId, orgId, loginName, displayName,null, userId);

        //记录日志
        oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.DELETE, Oplog.CODE.ORGUSER, userId);

        return ret;
    }

    @Override
    public int deletePositionUser(String tenantId, String loginName, String displayName,
                                  String orgId, String posId, String userId) {
        POrgUserPos oup = new POrgUserPos();
        oup.setTenantId(tenantId);
        oup.setOrgId(orgId);
        oup.setPosId(posId);
        oup.setUserId(userId);
        int rs = mDao.insert(Mapper.POrgUserPosMapper, "deleteByObj", oup);

        //记录日志
        oplog.bizlog(tenantId, loginName, displayName, null, Oplog.OP.DELETE, Oplog.CODE.POSUSER, userId);

        return rs;
    }

    @Override
    public String usersInOrgDhx(String tenantId, String orgId, String queryParams, int fInd, int lInd, int timezoneOffset, String lang, String ordercolumns) {
        log.debug("usersInOrgDhx queryParams="+queryParams);
        Map<String, Object> params = new HashMap<String,Object>();
        params.put("orgId", orgId);
        if (tenantId!=null) {
            params.put(Const.TENANT_ID, tenantId);
        }
        if (queryParams!=null) {
            params.putAll(JSONObject.parseObject(queryParams));
        }
        params.put("orderby", DhxUtil.parseGridOrderBy(ordercolumns));
        log.debug("query params="+params);
        PageHelper.offsetPage(fInd-1, lInd - fInd + 1);
        List<Map<String,?>> list = mDao.selectList(Mapper.PUserMapper, "selectUsersByOrgDhx", params);
        String[] cols = new String[]{"LOGIN_NAME", "DISPLAY_NAME", "USER_TYPE"};
        PageInfo page = new PageInfo(list);
        String rtn= DhxUtil.toGridJsonStr(list,
                cols, fInd, (int)page.getTotal(), timezoneOffset, lang);
        log.debug("usersInOrgDhx returns:\n"+rtn);
        return rtn;
    }

    private JSONObject beanToJSON(POrg org, int timezoneOffset) {
        JSONObject node = new JSONObject();
        node.put("id", org.getOrgId());
        node.put("parent", org.getParentId());
        node.put("text", org.getOrgName());
        node.put("desc", org.getOrgDesc());
        node.put("type", org.getOrgType());
        node.put("creatorName", org.getCreatorName());
        node.put("createTime", DateUtil.formatDate(org.getCreateTime(), DateUtil.DATEFORMATSS_ZH, timezoneOffset));
        return node;
    }

    private JSONObject posBeanToJSON(Map<String, Object> pos, int timezoneOffset) {
        JSONObject node = new JSONObject();
        node.put("id", pos.get("ORG_ID")+"_"+pos.get("POS_ID"));
        node.put("parent", pos.get("ORG_ID"));
        node.put("text", pos.get("POS_NAME"));
        node.put("desc", pos.get("POS_DESC"));
        node.put("type", "POS");
        return node;
    }
}
